package top.blackr.folivora.common.security.crud.repository;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.repository.CrudRepository;
import lombok.AllArgsConstructor;
import net.dreamlu.mica.core.utils.BeanUtil;
import net.dreamlu.mica.core.utils.WebUtil;
import net.dreamlu.mica.redis.cache.MicaRedisCache;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import top.blackr.folivora.common.core.constants.RedisConstants;
import top.blackr.folivora.common.core.enums.ResultEnum;
import top.blackr.folivora.common.core.exception.BizException;
import top.blackr.folivora.config.ApplicationProperties;
import top.blackr.folivora.common.security.auth.SecUser;
import top.blackr.folivora.common.security.auth.SecurityUtils;
import top.blackr.folivora.common.security.event.UserLoginEvent;
import top.blackr.folivora.common.security.event.UserRegisterEvent;
import top.blackr.folivora.common.security.crud.mapper.SysUserMapper;
import top.blackr.folivora.common.security.crud.model.entity.SysUser;
import top.blackr.folivora.common.security.crud.model.entity.SysUserRole;
import top.blackr.folivora.common.security.crud.model.vo.SysMenuVo;
import top.blackr.folivora.common.security.crud.model.vo.SysRoleVo;
import top.blackr.folivora.common.security.crud.model.vo.SysUserVo;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Component
@AllArgsConstructor
public class SysUserRepository extends CrudRepository<SysUserMapper, SysUser> {

    private final SysUserRoleRepository sysUserRoleRepository;
    private final SysRoleRepository roleRepository;
    private final SysMenuRepository menuRepository;
    private final MicaRedisCache redisCache;
    private final ApplicationEventPublisher eventPublisher;
    private final ApplicationProperties.Security securityProperties;

    public SysUserVo loginForUsername(String username) {
        // 查询用户信息
        SysUser sysUser = baseMapper.selectOne(Wrappers.<SysUser>lambdaQuery()
                .eq(SysUser::getUsername, username)
                .eq(SysUser::getDelFlag, 0)
                .last("limit 1"));
        SysUserVo userVo = constructUserInfo(sysUser);
        eventPublisher.publishEvent(new UserLoginEvent(this, sysUser));
        return userVo;
    }


    public SysUserVo loginForWx(String openid) {
        // 查询用户信息
        SysUser sysUser = baseMapper.selectOne(Wrappers.<SysUser>lambdaQuery()
                .eq(SysUser::getWxOpenid, openid)
                .eq(SysUser::getDelFlag, 0)
                .last("limit 1"));
        SysUserVo userVo = constructUserInfo(sysUser);
        eventPublisher.publishEvent(new UserLoginEvent(this, sysUser));
        return userVo;
    }


    public SysUserVo loginForSms(String phone) {
        // 查询用户信息
        SysUser sysUser = baseMapper.selectOne(Wrappers.<SysUser>lambdaQuery()
                .eq(SysUser::getPhone, phone)
                .eq(SysUser::getDelFlag, 0)
                .last("limit 1"));
        SysUserVo userVo = constructUserInfo(sysUser);
        eventPublisher.publishEvent(new UserLoginEvent(this, sysUser));
        return userVo;
    }


    public Page<SysUserVo> userInfoPage(Page<SysUserVo> page, SysUserVo params) {
        if (!SecurityUtils.isAdmin() && ObjectUtil.isEmpty(params.getPhone())) {
            return new Page<>();
        }
        SecUser user = SecurityUtils.getUser();
        params.setUserId(user.getUserId());
        params.setDeptId(user.getDeptId());
        return baseMapper.userInfoPage(page, params);
    }


    public boolean registerForWx(SysUserVo userVo) {
        SysUser sysUser = new SysUser();
        BeanUtil.copyProperties(userVo, sysUser);
        sysUser.setUsername(sysUser.getWxOpenid());
        sysUser.setPassword(SaSecureUtil.aesEncrypt(securityProperties.getKey(), RandomUtil.randomString(9)));
        this.save(sysUser);
        // 角色
        SysUserRole sysUserRole = new SysUserRole();
        sysUserRole.setUserId(sysUser.getUserId());
        sysUserRole.setRoleId(2);
        sysUserRoleRepository.save(sysUserRole);
        eventPublisher.publishEvent(new UserRegisterEvent(this, sysUser));
        return true;
    }


    public String resetPwd(SysUserVo params) {
        Long userId = params.getUserId();
        if (userId == 1) {
            return "你想干嘛？？？";
        }
        String password = params.getPassword();
        String newPwd = RandomUtil.randomString(9);
        // 重置或修改密码
        SysUser user = new SysUser();
        user.setUserId(userId);
        user.setPassword(SaSecureUtil.aesEncrypt(securityProperties.getKey(), newPwd));
        if (StrUtil.isNotEmpty(password)) {
            user.setPassword(SaSecureUtil.aesEncrypt(securityProperties.getKey(), password));
        }
        this.updateById(user);
        // 删除缓存
        SysUser byId = this.getById(userId);
        redisCache.del(RedisConstants.User.USER_INFO_USERNAME + byId.getUsername());
        String token = WebUtil.getRequest().getHeader(HttpHeaders.AUTHORIZATION);
        redisCache.del(RedisConstants.TOKEN_CACHE_KEY + token);
        return newPwd;
    }


    @Caching(evict = {
            @CacheEvict(cacheNames = RedisConstants.User.USER_INFO_USERNAME, key = "#sysUser.username", condition = "#sysUser.username != null"),
    })
    public void updateCacheById(SysUser sysUser) {
        this.updateById(sysUser);
    }


    public Object getPages(Page<SysUserVo> page, SysUserVo params) {
        return baseMapper.getPages(page, params);
    }

    @Cacheable(value = RedisConstants.User.USER_INFO_USERNAME, key = "#user.username", unless = "#result == null")
    public SysUserVo constructUserInfo(SysUser user) {
        if (ObjectUtil.isEmpty(user)) {
            throw new BizException(ResultEnum.FAIL);
        }
        // 查询用户的角色信息
        Set<SysRoleVo> roles = roleRepository.getRolesByUserId(user.getUserId());
        List<Integer> roleIds = roles.stream().map(SysRoleVo::getRoleId).collect(Collectors.toList());
        // 查询角色关联的菜单、权限信息
        List<SysMenuVo> menus = menuRepository.getMenusByRoleIds(roleIds);
        SysUserVo userInfo = new SysUserVo();
        BeanUtil.copyProperties(user, userInfo);
        userInfo.setRoles(roles);
        userInfo.setMenus(menus);
        return userInfo;
    }
}
